#include "StdThreadPool.h"
#include <cstddef>
#include <unistd.h>


class Task
{
public:
    Task(void* (funcPtr)(void*),void* arg)
    {
        this->funcPtr = funcPtr;
        arg = arg;
    }
    ~Task()
    {
        delete arg;
    }
    void* (func)(void*)
    {
        return func(arg);
    }
public:
    void* (*funcPtr)(void*);
    void* arg;
};


struct ThreadPrivate
{
    std::mutex mtx;
    std::list<std::thread> threads;//线程链表 
    std::queue<Task> taskQueue;//任务队列
    int MaxThreadNumber;//最大线程数
    int MinThreadNumber;//最小线程数
    int MaxQueueSize;//最大任务队列

    int BusyThreadNum;//忙碌线程数:有多少线程正在工作
    std::mutex BsyThreadMtx;//忙碌线程锁,专门控制上面的变量
    int minusNum;//需要被退出的线程数量
    std::unique_lock<std::mutex> poolMutex;//线程池的锁
    std::condition_variable queueNotEmpty;//队列不为空的条件变量
    std::condition_variable queueNotFull;//队列不为满的条件变量

    std::thread manager;//管理者线程
    int sleepTime;//管理者线程的检查周期

    bool shutDown;//关闭线程池标志
};

void *StdThreadPool::ThreadHandler()
{
    while(1)
    {
        p->poolMutex.lock();
        while(p->taskQueue.empty() == true && p->shutDown == false)
        {
            p->queueNotEmpty.wait(p->poolMutex);

            p->BsyThreadMtx.lock();
            if(p->minusNum == 0)
                p->BsyThreadMtx.unlock();
            else
            {
                p->threads.remove_if([](std::thread thread)->bool
                {
                    return std::this_thread::get_id() == thread.get_id();
                });
                p->minusNum--;
                p->BsyThreadMtx.unlock();
                p->poolMutex.unlock();

                return NULL;
            }
        }
        if(p->shutDown == true)
        {
            p->poolMutex.unlock();
            return NULL;
        }
        //有任务唤醒，从任务队列中将任务取出
        //GetQFront取的是值的指针的指针
        Task *t = (Task*)(&p->taskQueue.front());
        p->taskQueue.pop();
        //有任务被取出，可以向任务队列中加任务
        p->queueNotFull.notify_all();
        p->poolMutex.unlock();

        //准备忙任务
        p->BsyThreadMtx.lock();
        p->BusyThreadNum++;
        p->BsyThreadMtx.unlock();

        //做任务  
        t->funcPtr(t->arg);
        t->~Task();

        //线程闲下来了，没有工作要处理
        p->BsyThreadMtx.lock();
        p->BusyThreadNum--;
        p->BsyThreadMtx.unlock();
    }
}

void* StdThreadPool::ThreadManager()
{
    while(p->shutDown == false)
    {
        sleep(p->sleepTime);
        p->poolMutex.lock();

        if(p->taskQueue.size() > p->threads.size() && p->threads.size() < p->MaxThreadNumber)
        {
            int MaxAddNum = p->MaxThreadNumber - p->threads.size();
            int shouldAddNum = p->taskQueue.size() / 2;
            int addNum = MaxAddNum>shouldAddNum?shouldAddNum:MaxAddNum;
            for(int i = 0; i < addNum; i++)
            {
                p->threads.push_back(std::thread(ThreadHandler(),p));
            }
        }
        p->BsyThreadMtx.lock();
        if(p->BusyThreadNum * 2 < p->threads.size() && p->threads.size() > p->MinThreadNumber)
        {
            int MaxMinusNum = p->threads.size() - p->MinThreadNumber;//能减去的最大的线程数量
            int shouldMinusNum = (p->threads.size() - p->BusyThreadNum) / 2;//应该要减去的线程数量
            int minusNum = MaxMinusNum > shouldMinusNum ? shouldMinusNum : MaxMinusNum;
            for(int i = 0 ; i < minusNum; i++)
                p->queueNotEmpty.notify_one();
        }
        p->BsyThreadMtx.unlock();
        p->poolMutex.unlock();
    }
}

void StdThreadPool::AddPoolTask(void *(*funcPtr)(void *), void *arg)
{
    p->poolMutex.lock();
    while(p->taskQueue.size() == p->MaxQueueSize && p->shutDown == false)
    {
        //等待队列不满的条件
        p->queueNotEmpty.wait(p->poolMutex);
    }
    //线程池准备退出，线程退出
    if(p->shutDown == true)
    {
        p->poolMutex.unlock();
        return;
    }
    //添加任务
    p->taskQueue.push(Task(funcPtr,arg));
    //唤醒线程
    p->queueNotEmpty.notify_one();
    p->poolMutex.unlock();
}

StdThreadPool::StdThreadPool(int MaxThreadNumber,int MinThreadNumber,int MaxQueueSize,int second)
{
    p = new ThreadPrivate;
    p->MaxThreadNumber = MaxThreadNumber;
    p->MinThreadNumber = MinThreadNumber;
    p->MaxQueueSize = MaxQueueSize;
    p->sleepTime = second;
    p->minusNum = 0;
    p->BusyThreadNum = 0;
    p->manager = std::thread();
    p->shutDown = false;
}


StdThreadPool::~StdThreadPool()
{
    delete p;
    p->shutDown = true;
    p->manager.join();
    for(int i = 0; i < p->threads.size();i++)
    {
        p->queueNotEmpty.notify_one();
    }
}